package com.tao.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.oauth2.jwt.*;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.security.oauth2.server.resource.authentication.JwtReactiveAuthenticationManager;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import java.util.Objects;

@Configuration
public class GatewayTokenConfig {

    private static final String ISSUER_URI = "http://127.0.0.1:63070/auth";

    @Bean
    public JwtDecoder jwtDecoder() {
        return NimbusJwtDecoder.withJwkSetUri(ISSUER_URI + "/oauth2/jwks")
                .build();
    }

    @Bean
    public ReactiveJwtDecoder reactiveJwtDecoder() {
        return NimbusReactiveJwtDecoder.withJwkSetUri(ISSUER_URI + "/oauth2/jwks")
                .build();
    }
    @Bean
    public JwtReactiveAuthenticationManager jwtReactiveAuthenticationManager(
            ReactiveJwtDecoder reactiveJwtDecoder
    ) {
        return new JwtReactiveAuthenticationManager(reactiveJwtDecoder);
    }

    @Bean
    public WebFilter jwtContextWebFilter() {
        return (ServerWebExchange exchange, WebFilterChain chain) ->
                ReactiveSecurityContextHolder.getContext()
                        .map(SecurityContext::getAuthentication)
                        .filter(Objects::nonNull)
                        .filter(authentication -> authentication instanceof JwtAuthenticationToken)
                        .map(authentication -> (JwtAuthenticationToken) authentication)
                        .map(JwtAuthenticationToken::getToken)
                        .map(jwt -> {
                            // 将 JWT 中的信息放入 ServerWebExchange 的上下文
                            exchange.getAttributes().put("userId", jwt.getClaimAsString("sub"));
                            exchange.getAttributes().put("authorities", jwt.getClaimAsStringList("authorities"));
                            return exchange;
                        })
                        .defaultIfEmpty(exchange)
                        .flatMap(chain::filter);
    }
}
